// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.api.ads.adwords.lib.utils;

import com.google.api.ads.adwords.lib.client.AdWordsSession;
import com.google.api.ads.common.lib.auth.AuthorizationHeaderProvider;
import com.google.api.ads.common.lib.exception.AuthenticationException;
import com.google.api.ads.common.lib.useragent.UserAgentCombiner;
import com.google.api.ads.common.lib.utils.Internals;
import com.google.common.annotations.VisibleForTesting;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Helper class that generates a configured HttpURLConnection for report downloads.
 *
 * @author Kevin Winter
 */
public class ReportUrlConnectionHelper {

  private static final Logger logger = LoggerFactory.getLogger(
      AdHocReportDownloadHelper.class.getPackage().getName() + ".report_download");

  /** The URI of the download server. */
  public static final String DOWNLOAD_SERVER_URI = "/api/adwords/reportdownload";

  /** HTTP Request Method */
  private static final String REQUEST_METHOD = "POST";

  private final AdWordsSession session;
  private final UserAgentCombiner userAgentCombiner;
  private final AuthorizationHeaderProvider authorizationHeaderProvider;

  /**
   * Constructor that gets an Internals instance from AdWordsInternals.
   *
   * @param session to use when making requests.
   */
  ReportUrlConnectionHelper(AdWordsSession session) {
    this(session, AdWordsInternals.getInstance());
  }

  /**
   * Constructor that uses internal utilities from the provided Internals object.
   *
   * @param session to use when making requests.
   */
  @VisibleForTesting
  ReportUrlConnectionHelper(AdWordsSession session, Internals internals) {
    this(session, internals.getAuthorizationHeaderProvider(), internals.getUserAgentCombiner());
  }

  /**
   * Constructor that takes all dependencies.
   *
   * @param session Used to pull authentication data.
   * @param authorizationHeaderProvider Used to population the authentication data into a header.
   * @param userAgentCombiner Used to populate the User-Agent header.
   */
  @VisibleForTesting
  ReportUrlConnectionHelper(AdWordsSession session,
      AuthorizationHeaderProvider authorizationHeaderProvider,
      UserAgentCombiner userAgentCombiner) {
    this.session = session;
    this.authorizationHeaderProvider = authorizationHeaderProvider;
    this.userAgentCombiner = userAgentCombiner;
  }

  /**
   * Gets the report HTTP URL connection given report URL and proper information needed to
   * authenticate the request.
   *
   * @param reportUrl the URL of the report response or download
   * @return the report HTTP URL connection
   * @throws MalformedURLException if the report URL could not be used
   * @throws IOException if there was a problem connecting to the URL
   * @throws ReportException if there were any other problems (such as errors with OAuth).
   * @throws AuthenticationException if the authorization header could not be
   *         created
   */
  @VisibleForTesting
  HttpURLConnection getReportHttpUrlConnection(String reportUrl)
      throws MalformedURLException, IOException, ReportException, AuthenticationException {
    HttpURLConnection httpUrlConnection = (HttpURLConnection) new URL(reportUrl).openConnection();
    httpUrlConnection.setRequestMethod(REQUEST_METHOD);
    logger.info("{} {}", REQUEST_METHOD, reportUrl);

    httpUrlConnection.setRequestProperty(
        "Authorization", authorizationHeaderProvider.getAuthorizationHeader(session, reportUrl));

    String userAgent = userAgentCombiner.getUserAgent(session.getUserAgent());
    httpUrlConnection.setRequestProperty("User-Agent", userAgent);
    logger.info("User-Agent: {}", userAgent);
    httpUrlConnection.setRequestProperty("developerToken", session.getDeveloperToken());
    logger.info("developerToken: {}", session.getDeveloperToken());
    httpUrlConnection.setRequestProperty("clientCustomerId", session.getClientCustomerId());
    logger.info("clientCustomerId: {}", session.getClientCustomerId());
    httpUrlConnection.setRequestProperty("returnMoneyInMicros", Boolean.toString(
        session.isReportMoneyInMicros()));
    logger.info("returnMoneyInMicros: {}", session.isReportMoneyInMicros());

    return httpUrlConnection;
  }
}
